#include "IssuerSearch.h"

#include <bondlib/Pinyin.h>
#include <bondlib/QBIssuerInfo.h>
#include <core/strings/string_util.h>

#include <QJsonObject>
#include <thread>

#include "QbBondModule.h"

using namespace qb::base;

class compare_shortname2 {
 public:
  compare_shortname2() {}
  bool operator()(int index1, int index2) {
    if (index1 == index2) return false;
    CQBIssuerInfo& IInfo = CQBIssuerInfo::instance();
    const IssuerInfo* pIssuer1 = IInfo.GetIssuerInfoByIndex(index1);
    const IssuerInfo* pIssuer2 = IInfo.GetIssuerInfoByIndex(index2);
    if (!pIssuer1 || !pIssuer2) return false;
    const char* name1 = pIssuer1->field((int)kIssuerInfo::Full_Name_C);
    const char* name2 = pIssuer2->field((int)kIssuerInfo::Full_Name_C);
    return strcmp(name1, name2) < 0;
  }
} sort_shortname2;

void IssuerSearchEngine::search(int serialNum, const QString& key) {
  m_curSearchSerialNum = serialNum;
  QString searchKey = key.toUpper();
  std::thread t([=]() {
    { std::lock_guard<std::mutex> locker(m_lock); }

    doSearch(serialNum, searchKey);
  });
  t.detach();
}

void IssuerSearchEngine::setUserData(int userdata) { m_userdata = userdata; }

void IssuerSearchEngine::setResultCallback(
    std::function<void(int, QJsonArray)> fun) {
  m_fun = fun;
}

bool IssuerSearchEngine::isMatch(const CBondInfo& info, const char* text,
                                 int len, bool bIsAllNumber) {
  return false;
}

void IssuerSearchEngine::onResultSelected(const QString& key) {}

void IssuerSearchEngine::doSearch(int serialNum, const QString& key) {
#ifndef _MSC_VER
  char* pstr = strdup(key.toLocal8Bit().data());
#else
  char* pstr = _strdup(key.toLocal8Bit().data());
#endif

  int lenMatchTxt = strlen(pstr);
  bool isCh = false;
  for (int i = 0; i < lenMatchTxt; i++) {
    if (pstr[i] < 0 || pstr[i] > 127) {
      isCh = true;
      break;
    }
  }

  int flag = m_userdata;

  CQBIssuerInfo& IInfo = [=](int f) -> CQBIssuerInfo& {
    switch (f) {
      case issuerUnderwriter:
        return CQBIssuerInfo::MainUnderwriterContainer();
        break;
      case issuerAbsSeries:
        return CQBIssuerInfo::ABSBondSeries();
        break;
      case issuerAbsFinancier:
        return CQBIssuerInfo::ABSBondFinancier();
        break;
      case issuerGuarantor:
        return CQBIssuerInfo::GuarantorInstitution();
        break;
      case issuerNormal:
      default:
        return CQBIssuerInfo::instance();
        break;
    }
  }(flag);

  int count = 0;
  int exactmatchIndex = -1;
  std::vector<int> matchIndex;
  int issuerCount = IInfo.GetAllIssuerCount();
  for (int index = 0; index < issuerCount; index++) {
    if (count >= 200) break;
    const IssuerInfo* pIssuer = IInfo.GetIssuerInfoByIndex(index);
    if (!pIssuer) continue;
    bool found = false;

    do {
      // 全称匹配
      const char* matchStr = pIssuer->field((int)kIssuerInfo::Full_Name_C);
      found = (nullptr != StringUtil::_strstr_cn(matchStr, pstr));
      if (found) {
        if (strlen(matchStr) == lenMatchTxt) exactmatchIndex = index;
        break;
      }
      if (isCh) break;

      // 英文全称匹配
      matchStr = pIssuer->field((int)kIssuerInfo::Full_Name_E);
      found = (nullptr != StringUtil::_strstr_cn(matchStr, pstr));
      if (found) {
        if (strlen(matchStr) == lenMatchTxt) exactmatchIndex = index;
        break;
      }

      qb::PinyinManager& pyMgr = qb::PinyinManager::instance();
      std::string sJianpin, sQuanpin;
      pyMgr.GetPinyin(pIssuer->field((int)kIssuerInfo::Full_Name_C), sJianpin,
                      sQuanpin);
      // 简拼匹配
      found = (nullptr != StringUtil::_strstr_cn(sJianpin.c_str(), pstr));
      if (found) {
        if (sJianpin.size() == lenMatchTxt) exactmatchIndex = index;
        break;
      }

      found = (nullptr !=
               StringUtil::_strstr_cn(sQuanpin.c_str(), pstr));  // 全拼匹配
      if (found) {
        if (sQuanpin.size() == lenMatchTxt) exactmatchIndex = index;
        break;
      }
    } while (0);

    if (found) {
      if (exactmatchIndex != index) matchIndex.push_back(index);
      ++count;
    }
  }

  if (count > 0) {
    QJsonArray results;
    std::sort(matchIndex.begin(), matchIndex.end(), sort_shortname2);
    if (exactmatchIndex != -1) {
      QJsonArray result;
      result.push_back(QString::number(exactmatchIndex));
      const IssuerInfo* pIssuer = IInfo.GetIssuerInfoByIndex(exactmatchIndex);
      result.push_back(QString::fromLocal8Bit(
          pIssuer->field((int)kIssuerInfo::Full_Name_C)));
      results.push_back(result);
    }
    for (auto& i : matchIndex) {
      QJsonArray result;
      result.push_back(QString::number(i));
      const IssuerInfo* pIssuer = IInfo.GetIssuerInfoByIndex(i);
      if (!pIssuer) continue;
      result.push_back(QString::fromLocal8Bit(
          pIssuer->field((int)kIssuerInfo::Full_Name_C)));
      results.push_back(result);
    }

    {
      std::lock_guard<std::mutex> locker(m_lock);
      m_fun(m_curSearchSerialNum, results);
    }
  }

  if (pstr) free(pstr);
}
